package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.MessageException;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.model.TechnologyStackDto;
import com.uinnova.product.eam.model.dto.EamDataSetClassDto;
import com.uinnova.product.eam.model.dto.EamTableFriendDto;
import com.uinnova.product.eam.model.dto.ServiceAnalysisConfig;
import com.uinnova.product.eam.service.ICIDataSetSvc;
import com.uinnova.product.eam.service.ICIRltSwitchSvc;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.comm.model.ci.CcCiClass;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.product.vmdb.provider.rlt.bean.CcCiRltInfo;
import com.uino.api.client.cmdb.*;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.base.dataset.*;
import com.uino.bean.cmdb.base.dataset.batch.DataSetExeResult;
import com.uino.bean.cmdb.business.dataset.DataSetExeResultSheetPage;
import com.uino.bean.cmdb.business.dataset.FriendInfo;
import com.uino.bean.cmdb.query.ESRltSearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.dao.cmdb.dataset.ESDataSetExeResultSvc;
import com.uino.service.cmdb.dataset.microservice.IRelationRuleAnalysisBase;
import com.uino.util.sys.SysUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据超市相关服务，所有通过数据超市或者上下几层查询CI的接口都在此服务中
 *
 * @author yuhao.guan
 * @version 2020-7-14
 */
@Deprecated
@Service
public class IamsCIDataSetSvc implements ICIDataSetSvc {

    private static Logger logger = LoggerFactory.getLogger(IamsCIDataSetSvc.class);

    @Value("${http.resource.space}")
    private String httpResourceUrl;

    @Autowired
    private ICIApiSvc iciApiSvc;

    @Autowired
    private ICISwitchSvc ciSwitchSvc;

    @Autowired
    private ICIRltSwitchSvc ciRltSwitchSvc;

    @Resource
    private IRltClassApiSvc rltClassApiSvc;

    @Autowired
    private ICIRltApiSvc iciRltApiSvc;

    @Autowired
    private IDataSetApiSvc dataSetApiSvc;

    @Resource
    private ICIClassApiSvc ciClassApiSvc;

    @Resource
    private BmConfigSvc bmConfigSvc;

    @Autowired
    private IRelationRuleAnalysisBase relationRuleAnalysisBase;

    @Autowired
    private ESDataSetExeResultSvc esDataSetExeResultSvc;

/*    @Value("${dataSet.technology.stack}")
    private Long technologyStackDataSetId;*/

    //@Override
    public ICIApiSvc getCiApiSvc() {
        return iciApiSvc;
    }

    public ICIRltApiSvc getCiRltApiSvc() {
        return iciRltApiSvc;
    }

    @Override
    public TechnologyStackDto queryAppTechnologyStack(LibType libType, Long technologyStackDataSetId, Long startCiId) {
        // 使用数据超市返回结果
        FriendInfo friendInfo = queryFriendByStartCiId(libType, technologyStackDataSetId, startCiId);
        // 关系层次映射(数据超市返回关系分为三层，0:起始CI，1:技术栈，2:技术组件)
        Map<Long, Set<Long>> nodeMap = friendInfo.getCiIdByNodeMap();
        // 技术栈包含的CiId
        Set<Long> technologyStackNodes = nodeMap.get(1L);
        // 技术组件包含的CiId
        Set<Long> technologyComponentNodes = nodeMap.get(2L);

        TechnologyStackDto retDto = new TechnologyStackDto();
        List<CcCiInfo> ciInfoList = friendInfo.getCiNodes();
        List<CcCiInfo> stackList = new ArrayList<>();
        List<CcCiInfo> componentList = new ArrayList<>();
        for (CcCiInfo ciInfo : ciInfoList) {
            if (technologyStackNodes.contains(ciInfo.getCi().getId())) {
                stackList.add(ciInfo);
            } else if (technologyComponentNodes.contains(ciInfo.getCi().getId())) {
                componentList.add(ciInfo);
            }
        }
        retDto.setStackList(stackList);
        retDto.setComponentList(componentList);
        return retDto;
    }

    @Override
    public List<CcCiInfo> queryRelatedCIByDataSet(LibType libType, Long dataSetId, Long startCiId) {
        // 使用数据超市返回结果
        FriendInfo friendInfo = queryFriendByStartCiId(libType, dataSetId, startCiId);
        // 关系层次映射(数据超市返回关系分为两层，0:起始CI，1:关联的CI)
        Map<Long, Set<Long>> nodeMap = friendInfo.getCiIdByNodeMap();
        if (nodeMap == null) {
            return new ArrayList<>(0);
        }
        // 第1层包含的CiId
        Set<Long> relatedNodes = nodeMap.get(1L);
        List<CcCiInfo> ciInfoList = friendInfo.getCiNodes();
        List<CcCiInfo> relatedCiList = new ArrayList<>();
        if (relatedNodes != null && relatedNodes.size() > 0) {
            for (CcCiInfo ciInfo : ciInfoList) {
                if (relatedNodes.contains(ciInfo.getCi().getId())) {
                    relatedCiList.add(ciInfo);
                }
            }
        }
        return relatedCiList;
    }

    @Override
    public FriendInfo queryFriendByStartCiId(LibType libType, Long dataSetId, Long startCiId) {
        FriendInfo friendInfo = new FriendInfo();
        try {
            if (LibType.BASELINE.equals(libType)) {
                friendInfo = dataSetApiSvc.queryFriendByStartCiId(dataSetId, startCiId);
            } else {
                friendInfo = queryFriendByStartCiIdByLibType(libType, dataSetId, startCiId);
            }
        } catch (Exception e) {
            logger.error("Query friend info error", e);
        }
        return friendInfo;
    }

    @Override
    public JSONObject queryDataSetByName(String dataSetName, String url) {
        JSONObject retObj = new JSONObject();
        // 模糊查询到数据集列表
        List<JSONObject> dataSetList = dataSetApiSvc.findDataSet(dataSetName, false, null, null);

        // 找到名称一致的数据集
        for (JSONObject dataSetJson : dataSetList) {
            if (dataSetName.equals(dataSetJson.getString("name"))) {
                retObj = dataSetJson;
            }
        }
        return retObj;
    }

    @Override
    public List<CcCiInfo> queryRelatedListCIInfo(long ciId, LibType libType) {

        CcCiInfo ciInfo = ciSwitchSvc.getCiInfoById(ciId,libType);
        Map<String, String> attrs = ciInfo.getAttrs();
        List<CcCiInfo> realComponentList = new ArrayList<>();
        String guidelineCiCode = attrs.get("所使用的技术栈参考标准");
        if (!StringUtils.isEmpty(guidelineCiCode)) {
            ESRltSearchBean searchBean = new ESRltSearchBean();
            Set<String> ciCodes = new HashSet<>();
            ciCodes.add(guidelineCiCode);
            searchBean.setSourceCiCodes(ciCodes);
            searchBean.setPageSize(5000);
            Page<CcCiRltInfo> ccCiRltInfoPage = ciRltSwitchSvc.searchRltByBean(searchBean, libType);
            List<CcCiRltInfo> data = ccCiRltInfoPage.getData();
            for (CcCiRltInfo ccCiRltInfo : data) {
                realComponentList.add(ccCiRltInfo.getTargetCiInfo());
            }
            return realComponentList;
        } else {
            return null;
        }
    }

    @Override
    public Map<String, Map<String, Object>> getResultMap(List<CcCiInfo> realComponentList, List<CcCiInfo> componentList) {
        List<CcCiInfo> standardTechSTack = new ArrayList<>();
        List<CcCiInfo> noStandardTechStack = new ArrayList<>();
        boolean flag = false;
        //如果一个系统没有绑定技术标准，那么系统使用的技术按非标准返回
        if (realComponentList == null) {
            Map<Boolean, List<CcCiInfo>> totalMap = new HashMap<>();
            totalMap.put(false, componentList);
            Map<String, Map<String, Object>> result = transerObjMap(totalMap, realComponentList);
            return result;
        } else {
            for (CcCiInfo bccCiInfo : componentList) {
                for (CcCiInfo rccCcCiInfo : realComponentList) {
                    if (bccCiInfo.getCi().getId().longValue() == rccCcCiInfo.getCi().getId().longValue()) {
                        standardTechSTack.add(bccCiInfo);
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    noStandardTechStack.add(bccCiInfo);
                }
                flag = false;
            }
            Map<Boolean, List<CcCiInfo>> totalMap = new HashMap<>();
            totalMap.put(true, standardTechSTack);
            totalMap.put(false, noStandardTechStack);
            //按照需要：如果系统使用的是非标准的技术栈需要返回系统标准的技术栈信息
            Map<String, Map<String, Object>> resultMap = transerObjMap(totalMap, realComponentList);
            return resultMap;
        }
    }

    @Override
    public List<EamDataSetClassDto> queryDataSetByNames(List<Long> ids, List<String> names, String like) {
        List<EamDataSetClassDto> result = new ArrayList<>();
        if(BinaryUtils.isEmpty(ids) && BinaryUtils.isEmpty(names)){
            return Collections.emptyList();
        }
        // 模糊查询到数据集列表
        List<JSONObject> dataSetAll = dataSetApiSvc.findDataSet(null, false, null, null);
        List<JSONObject> dataSetList;
        if(!BinaryUtils.isEmpty(ids)){
            dataSetList = dataSetAll.stream().filter(each -> ids.contains(each.getLong("id"))).collect(Collectors.toList());
            dataSetList.sort(Comparator.comparing(each -> ids.indexOf(each.getLong("id"))));
        }else{
            //名称去重
            List<String> disNames = names.stream().distinct().collect(Collectors.toList());
            dataSetList = dataSetAll.stream().filter(each -> disNames.contains(each.getString("name"))).collect(Collectors.toList());
            dataSetList.sort(Comparator.comparing(each -> names.indexOf(each.getString("name"))));
        }
        List<Map> nodes = dataSetList.stream().map(each -> each.getJSONArray("nodes").toJavaList(Map.class)).flatMap(Collection::stream).collect(Collectors.toList());
        List<Long> classIds = nodes.stream().map(each -> Long.parseLong(each.get("classId").toString())).distinct().collect(Collectors.toList());
        List<ESCIClassInfo> classInfos = ciClassApiSvc.queryESClassInfoByIds(classIds);
        for (ESCIClassInfo classInfo : classInfos) {
            String icon = classInfo.getIcon();
            if (icon != null && !icon.startsWith(httpResourceUrl)) {
                icon = httpResourceUrl + icon;
                classInfo.setIcon(icon);
            }
        }
        Map<Long, ESCIClassInfo> ciClassMap = classInfos.stream().collect(Collectors.toMap(CcCiClass::getId, each -> each));
        // 找到名称一致的数据集
        for (JSONObject dataSetJson : dataSetList) {
            List<Map> nodeList = dataSetJson.getJSONArray("nodes").toJavaList(Map.class);
            if(CollectionUtils.isEmpty(nodeList) || dataSetJson.getInteger("shareLevel").equals(OperateType.Invisible.getCode())){
                continue;
            }
            EamDataSetClassDto dto = new EamDataSetClassDto();
            dto.setId(dataSetJson.getLong("id"));
            dto.setName(dataSetJson.getString("name"));
            dto.setClassId(dataSetJson.getLong("classId"));
            dto.setPermissionLevel(dataSetJson.getInteger("permissionLevel"));
            List<Long> curClassIds = nodeList.stream().map(each -> Long.parseLong(each.get("classId").toString())).collect(Collectors.toList());
            List<CcCiClass> classList = curClassIds.stream().map(ciClassMap::get).filter(Objects::nonNull).collect(Collectors.toList());
            if(BinaryUtils.isEmpty(classList)){
                continue;
            }
            dto.setCiClassList(classList);
            result.add(dto);
        }
        if(!BinaryUtils.isEmpty(result)){
            List<Long> dataSetIds = result.stream().map(EamDataSetClassDto::getId).collect(Collectors.toList());
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            query.must(QueryBuilders.termsQuery("dataSetId", dataSetIds));
            if(!BinaryUtils.isEmpty(like)){
                query.must(QueryBuilders.wildcardQuery("startCi.ci.ciLabel.keyword", "*" + like + "*"));
            }
            Page<DataSetExeResult> listByQuery = esDataSetExeResultSvc.getListByQuery(1, 1000, query);
            List<DataSetExeResult> dataSetDetail = listByQuery.getData();
            Map<Long, List<DataSetExeResult>> dataSetGroup = dataSetDetail.stream().collect(Collectors.groupingBy(DataSetExeResult::getDataSetId));
            for (EamDataSetClassDto each : result) {
                ESCIClassInfo classInfo = ciClassMap.get(each.getClassId());
                if(BinaryUtils.isEmpty(classInfo)){
                    continue;
                }
                each.setAttrDefs(classInfo.getCcAttrDefs());
                classInfo.setAttrDefs(null);
                classInfo.setCcAttrDefs(null);
                each.setCiClass(classInfo);
                List<DataSetExeResult> exeList = dataSetGroup.get(each.getId());
                int count = 0;
                if(!BinaryUtils.isEmpty(exeList)){
                    //暂做去重处理
                    List<String> codeList = exeList.stream().map(s -> s.getStartCi().getCi().getCiCode()).distinct().collect(Collectors.toList());
                    count = codeList.size();
                }
                each.setCiCount((long) count);
            }
        }
        if(CollectionUtils.isEmpty(result)){
            throw new ServiceException("未查询到可用数据集!");
        }
        return result;
    }

    @Override
    public DataSetExeResultSheetPage queryTableFriend(EamTableFriendDto body) {
        SysUser user = SysUtil.getCurrentUserInfo();
        DataSetExeResultSheetPage result = dataSetApiSvc.queryDataSetResultBySheet(user.getDomainId(), body.getDataSetId(),
                body.getSheetId(), 1, 1000, body.getSortCol(), body.getIsDesc(), body.getCondition(), user.getLoginCode());
        CCcCi cdt = new CCcCi();
        cdt.setId(body.getStartCiId());
        List<CcCiInfo> rootCiList = iciApiSvc.queryCiInfoList(user.getDomainId(), cdt, null, true, false);
        if(BinaryUtils.isEmpty(rootCiList)) {
            throw new ServiceException("未找到根节点ci信息！");
        }
        CcCiInfo rootCi = rootCiList.get(0);
        Long rootClassId = rootCi.getCi().getClassId();
        Map<String, List<Map<String, String>>> headerGroup = result.getHeaders().stream().collect(Collectors.groupingBy(each -> each.get("classId")));
        List<Map<String, String>> rootHead = headerGroup.get(rootClassId.toString());
        String attrKey = rootHead.get(0).get("attrKey");
        String attrName = rootHead.get(0).get("attrName");
        String checkName = rootCi.getAttrs().get(attrName);
        List<Map<String, Object>> removeList = new ArrayList<>();
        List<String> keyList = result.getHeaders().stream().map(each -> each.get("attrKey")).collect(Collectors.toList());
        for (Map<String, Object> data : result.getData()) {
            Object checkObj = data.get(attrKey);
            if(BinaryUtils.isEmpty(checkObj) || !checkName.equals(checkObj.toString())){
                removeList.add(data);
                continue;
            }
            //判断header是否缺少字段
            Set<String> dataKey = data.keySet();
            if(dataKey.size() != keyList.size()){
                for (String key : keyList) {
                    if(!dataKey.contains(key)){
                        data.put(key, "");
                    }
                }
            }
        }
        result.setCount(getHeaderCount(rootHead));
        result.getData().removeAll(removeList);
        if(!BinaryUtils.isEmpty(result.getData())){
            List<Long> classIds = result.getHeaders().stream().map(each -> Long.parseLong(each.get("classId"))).distinct().collect(Collectors.toList());
            List<ESCIClassInfo> classInfos = ciClassApiSvc.queryESClassInfoByIds(classIds);
            Map<Long, ESCIClassInfo> classMap = classInfos.stream().collect(Collectors.toMap(CcCiClass::getId, each -> each, (key1, key2) -> key2));
            joinHeader(result, classMap, true);
        }
        return result;
    }

    private Integer getHeaderCount(List<Map<String, String>> headerList){
        Integer count = 0;
        for (Map<String, String> map : headerList) {
            String attrKey = map.get("attrKey");
            if(!BinaryUtils.isEmpty(attrKey) && attrKey.startsWith("0")){
                count++;
            }
        }
        return count;
    }

    @Override
    public List<DataSetExeResultSheetPage> queryTableFriendList(List<EamTableFriendDto> body) {
        SysUser user = SysUtil.getCurrentUserInfo();
        List<DataSetExeResultSheetPage> result = new ArrayList<>();
        List<Long> dataSetIds = body.stream().map(EamTableFriendDto::getDataSetId).distinct().collect(Collectors.toList());
        List<DataSetExeResultSheetPage> dataSetExeList = dataSetApiSvc.queryDataSetResultList(dataSetIds, body.get(0).getSheetId(), null, false);
        Long[] startCiIds = body.stream().map(EamTableFriendDto::getStartCiId).toArray(Long[]::new);
        CCcCi cdt = new CCcCi();
        cdt.setIds(startCiIds);
        List<CcCiInfo> rootCiList = iciApiSvc.queryCiInfoList(user.getDomainId(), cdt, null, true, false);
        if(BinaryUtils.isEmpty(rootCiList)) {
            throw new ServiceException("未找到根节点ci信息！");
        }
        Map<Long, DataSetExeResultSheetPage> resultMap = dataSetExeList.stream().collect(Collectors.toMap(DataSetExeResultSheetPage::getDataSetId, each -> each, (key1, key2) -> key2));
        Map<Long, CcCiInfo> ciIdMap = rootCiList.stream().collect(Collectors.toMap(each -> each.getCi().getId(), each -> each, (key1, key2) -> key2));
        Map<Long, List<Map<String, String>>> headerMap = dataSetExeList.stream().collect(Collectors.toMap(DataSetExeResultSheetPage::getDataSetId, DataSetExeResultSheetPage::getHeaders, (k1, k2) -> k2));
        for (EamTableFriendDto tableFriend : body) {
            DataSetExeResultSheetPage dataSetResult = EamUtil.copy(resultMap.get(tableFriend.getDataSetId()),DataSetExeResultSheetPage.class);
            CcCiInfo rootCi = ciIdMap.get(tableFriend.getStartCiId());
            List<Map<String, String>> rootHead = headerMap.get(tableFriend.getDataSetId());
            String attrKey = rootHead.get(0).get("attrKey");
            String attrName = rootHead.get(0).get("attrName");
            String checkName = rootCi.getAttrs().get(attrName);
            List<Map<String, Object>> removeList = new ArrayList<>();
            List<String> keyList = dataSetResult.getHeaders().stream().map(each -> each.get("attrKey")).collect(Collectors.toList());
            for (Map<String, Object> data : dataSetResult.getData()) {
                Object checkObj = data.get(attrKey);
                if(BinaryUtils.isEmpty(checkObj) || !checkName.equals(checkObj.toString())){
                    removeList.add(data);
                    continue;
                }
                //判断header是否缺少字段
                Set<String> dataKey = data.keySet();
                if(dataKey.size() != keyList.size()){
                    for (String key : keyList) {
                        if(!dataKey.contains(key)){
                            data.put(key, "");
                        }
                    }
                }
            }
            dataSetResult.setStartCiId(tableFriend.getStartCiId());
            dataSetResult.setCount(getHeaderCount(rootHead));
            dataSetResult.getData().removeAll(removeList);
            result.add(dataSetResult);
        }
        List<Long> classIds = result.stream().map(DataSetExeResultSheetPage::getHeaders).flatMap(each -> each.stream()
                                            .map(u -> Long.parseLong(u.get("classId")))).distinct().collect(Collectors.toList());
        List<ESCIClassInfo> classInfos = ciClassApiSvc.queryESClassInfoByIds(classIds);
        Map<Long, ESCIClassInfo> classMap = classInfos.stream().collect(Collectors.toMap(CcCiClass::getId, each -> each, (key1, key2) -> key2));
        //解决标题重复添加
        List<Long> filterList = new ArrayList<>();
        for (DataSetExeResultSheetPage dataSetExe : result) {
            if(BinaryUtils.isEmpty(dataSetExe.getData())){
                continue;
            }
            joinHeader(dataSetExe, classMap, !filterList.contains(dataSetExe.getDataSetId()));
            filterList.add(dataSetExe.getDataSetId());
        }
        return result;
    }

    private void joinHeader(DataSetExeResultSheetPage dataSetExe, Map<Long, ESCIClassInfo> classMap, boolean flag){
        if(flag){
            for (Map<String, String> header : dataSetExe.getHeaders()) {
                Long classId = Long.parseLong(header.get("classId"));
                ESCIClassInfo esciClassInfo = classMap.get(classId);
                if(BinaryUtils.isEmpty(esciClassInfo)){
                    continue;
                }
                String headerName = header.get("attrName");
                header.put("attrName", headerName+",["+esciClassInfo.getClassName()+"]");
            }
        }
        Map<String, String> noMap = new HashMap<>();
        noMap.put("attrKey", "序号");
        noMap.put("attrName", "序号");
        dataSetExe.getHeaders().add(0, noMap);
        for (int i = 0; i < dataSetExe.getData().size(); i++) {
            dataSetExe.getData().get(i).put("序号", i+1);
        }
    }

    /**
     * 获取对应类型的数据超市
     *
     * @param json 包含数据超市类型信息的JSON
     * @return 数据超市API
     */
    private DataSetMallApi getDataSetMallApi(JSONObject json) {
        int type = json.getIntValue("type");
        if (DataSetMallApiType.RelationRule.getCode().equals(type)) {
            return new DataSetMallApiRelationRule(json);
        } else if (DataSetMallApiType.CiClass.getCode().equals(type)) {
            return new DataSetMallApiCiClass(json);
        } else if (DataSetMallApiType.RelClass.getCode().equals(type)) {
            return new DataSetMallApiRelClass(json);
        } else {
            throw new RuntimeException("无此类型");
        }
    }

    /**
     * 获取指定CI的朋友圈信息
     *
     * @param libType CI库类型（私有/设计/运行/）
     * @param dataSetId 数据集ID
     * @param startCiId 起始CI ID
     *
     * @return 朋友圈信息
     */
    public FriendInfo queryFriendByStartCiIdByLibType(LibType libType, Long dataSetId, Long startCiId) {
        SysUser user = SysUtil.getCurrentUserInfo();
        try {
            JSONObject dataSet = dataSetApiSvc.findDataSetById(dataSetId);
            if(dataSet.getInteger("shareLevel").equals(OperateType.Invisible.getCode())){
                throw MessageException.i18n("DCV_BS_OBJ_DATASET_NO_PERMISSION");
            }
            DataSetMallApi dataSetMallApi = this.getDataSetMallApi(dataSet);

            DataSetMallApiRelationRule dataSetMallRelationApi = (DataSetMallApiRelationRule) dataSetMallApi;
            CCcCi cdt = new CCcCi();
            cdt.setId(startCiId);
            List<CcCiInfo> ciInfos = ciSwitchSvc.queryCiInfoList(user.getDomainId(), cdt, null, true, false, libType);
            Map<Long, FriendInfo> friendInfoMap = queryCiFriendByCiIdsAndRule(libType, ciInfos, dataSetMallRelationApi);
            FriendInfo friendInfo = friendInfoMap.get(ciInfos.get(0).getCi().getId());
            return friendInfo;
        } catch (Exception e) {
            logger.error("查询数据集异常: ", e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 查询指定CI列表的朋友圈信息
     *
     * @param libType CI库类型（私有/设计/运行/）
     * @param sCis 起始CI集合
     * @param relationRule 数据集关系
     *
     * @return 朋友圈集合
     */
    public Map<Long, FriendInfo> queryCiFriendByCiIdsAndRule(LibType libType, List<CcCiInfo> sCis, DataSetMallApiRelationRule relationRule) {
        return relationRuleAnalysisBase.queryCiFriendByCiIdsAndRule(sCis, relationRule, false,
                ciSwitchSvc.getCiSvc(libType), ciRltSwitchSvc.getCiRltSvc(libType));
    }


    /**
     * 技术栈对象转换
     *
     * @param totalMap 技术栈标准集合Map
     * @param realComponentList 应用系统使用的技术组件信息
     *
     * @return 包含层级信息的技术栈信息
     */
    private Map<String, Map<String, Object>> transerObjMap(Map<Boolean, List<CcCiInfo>> totalMap, List<CcCiInfo> realComponentList) {
        Map<String, Map<String, Object>> resultMap = new HashMap<>();
        for (boolean b : totalMap.keySet()) {
            if (b) {
                for (CcCiInfo ccCiInfo : totalMap.get(b)) {
                    String oneLeveType = ccCiInfo.getAttrs().get("技术层级名称");
                    Map<String, Object> oneLevelMap = resultMap.computeIfAbsent(oneLeveType, k -> new HashMap<>());
                    String twoLevelType = ccCiInfo.getAttrs().get("二级技术层级名称");
                    if (!StringUtils.isEmpty(twoLevelType)) {
                        Map<String, String> attrs = ccCiInfo.getAttrs();
                        attrs.put("isStandard", true + "");
                        oneLevelMap.put(twoLevelType, attrs);

                    } else {
                        String ciCode = ccCiInfo.getCi().getCiCode();
                        oneLevelMap.put(ciCode, ccCiInfo.getAttrs());
                    }
                }
            } else {
                for (CcCiInfo ccCiInfo : totalMap.get(b)) {
                    String oneLeveType = ccCiInfo.getAttrs().get("技术层级名称");
                    Map<String, Object> oneLevelMap = resultMap.computeIfAbsent(oneLeveType, k -> new HashMap<>());
                    String twoLevelType = ccCiInfo.getAttrs().get("二级技术层级名称");
                    if (!StringUtils.isEmpty(twoLevelType)) {
                        Map<String, String> ccCiInfoAttrs = ccCiInfo.getAttrs();
                        HashMap<String, Object> attrs = new HashMap<>(ccCiInfoAttrs);
                        ArrayList<Map<String, String>> list = new ArrayList<>();
                        attrs.put("StandardInformation",list);
                        for (CcCiInfo info : realComponentList) {
                            if (ccCiInfo.getAttrs().get("技术层级名称").equals(info.getAttrs().get("技术层级名称")) &&
                                    ccCiInfo.getAttrs().get("二级技术层级名称").equals(info.getAttrs().get("二级技术层级名称"))) {
                                HashMap<String, String> stringStringHashMap = new HashMap<>();
                                stringStringHashMap.put("组件英文简称",info.getAttrs().get("组件英文简称"));
                                stringStringHashMap.put("组件英文全称",info.getAttrs().get("组件英文全称"));
                                list.add(stringStringHashMap);
                            }
                        }
                        attrs.put("isStandard", false + "");
                        oneLevelMap.put(twoLevelType, attrs);
                    } else {
                        String ciCode = ccCiInfo.getCi().getCiCode();
                        oneLevelMap.put(ciCode, ccCiInfo.getAttrs());
                    }
                }
            }
        }
        return resultMap;
    }

    @Override
    public Map<Long, List<CcCiInfo>> serviceAnalysis(List<Long> rltIds) {
        List<CcCiRltInfo> rltInfoList = ciRltSwitchSvc.searchRltByIds(new HashSet<>(rltIds), LibType.DESIGN);
        if(BinaryUtils.isEmpty(rltInfoList)){
            return Collections.emptyMap();
        }
        String configString = bmConfigSvc.getConfigType(Env.NX_SERVICE_CONFIG);
        if (BinaryUtils.isEmpty(configString)) {
            throw new ServiceException("视图配置项" + Env.NX_SERVICE_CONFIG + "不存在!");
        }

        ServiceAnalysisConfig config = JSONObject.parseObject(configString, ServiceAnalysisConfig.class);
        String useRltName = config.getUseRltName(), belRltName = config.getBelRltName(), mapRltName = config.getMapRltName();
        CCcCiClass useRltQuery = new CCcCiClass();
        useRltQuery.setClassNames(new String[]{useRltName,belRltName,mapRltName});
        List<CcCiClassInfo> rltClassList = rltClassApiSvc.getRltClassByCdt(useRltQuery);
        Map<String, CcCiClassInfo> rltNameMap = rltClassList.stream().collect(Collectors.toMap(each -> each.getCiClass().getClassName(), each -> each, (key1, key2) -> key2));
        CcCiClassInfo useRlt = rltNameMap.get(useRltName);
        CcCiClassInfo belRlt = rltNameMap.get(belRltName);
        CcCiClassInfo mapRlt = rltNameMap.get(mapRltName);
        if(BinaryUtils.isEmpty(useRlt) || BinaryUtils.isEmpty(belRlt) || BinaryUtils.isEmpty(mapRlt)){
            return Collections.emptyMap();
        }
        CCcCiClass serviceQuery = new CCcCiClass();
        serviceQuery.setClassName(config.getServiceCiName());
        List<CcCiClassInfo> ciClassList = ciClassApiSvc.queryClassByCdt(serviceQuery);
        if(BinaryUtils.isEmpty(ciClassList)){
            return Collections.emptyMap();
        }
        //应用间关系
        CcCi appCi = rltInfoList.get(0).getSourceCiInfo().getCi();
        Long serviceClassId = ciClassList.get(0).getCiClass().getId();
        //查询源端ci调用的服务(调用关系)
        List<Long> useRltClassId = Collections.singletonList(useRlt.getCiClass().getId());
        List<CcCiRltInfo> useRltAll = ciRltSwitchSvc.getRltInfoByClassId(useRltClassId, appCi.getClassId(), serviceClassId, null, LibType.DESIGN);
        Map<String, List<CcCiRltInfo>> useRltGroup = useRltAll.stream().collect(Collectors.groupingBy(each -> each.getSourceCiInfo().getCi().getCiCode()));
        List<Long> belRltClassId = Collections.singletonList(belRlt.getCiClass().getId());
        List<CcCiRltInfo> belongRltAll = ciRltSwitchSvc.getRltInfoByClassId(belRltClassId, serviceClassId, appCi.getClassId(), null, LibType.DESIGN);
        Map<String, List<CcCiRltInfo>> belRltGroup = belongRltAll.stream().collect(Collectors.groupingBy(each -> each.getTargetCiInfo().getCi().getCiCode()));
        //查询映射关系数据(接口服务->接口服务)
        List<Long> mapRltClassId = Collections.singletonList(mapRlt.getCiClass().getId());
        List<CcCiRltInfo> mapRltAll = ciRltSwitchSvc.getRltInfoByClassId(mapRltClassId, serviceClassId, serviceClassId, null, LibType.DESIGN);
        Map<String, CcCiInfo> mapServiceMap = mapRltAll.stream().collect(Collectors.toMap(each -> each.getSourceCiInfo().getCi().getCiCode(), CcCiRltInfo::getTargetCiInfo, (key1, key2) -> key2));
        Map<Long, CcCiRltInfo> rltMap = rltInfoList.stream().collect(Collectors.toMap(each -> each.getCiRlt().getId(), each -> each, (key1, key2) -> key2));
        Map<Long, List<CcCiInfo>> result = new HashMap<>(16);
        for (Long rltId : rltIds) {
            List<CcCiInfo> list = new ArrayList<>();
            CcCiRltInfo ciRlt = rltMap.get(rltId);
            if(BinaryUtils.isEmpty(ciRlt)){
                result.put(rltId, Collections.emptyList());
                continue;
            }
            CcCi sourceCi = ciRlt.getSourceCiInfo().getCi();
            CcCi targetCi = ciRlt.getTargetCiInfo().getCi();
            List<CcCiRltInfo> useRltList = useRltGroup.get(sourceCi.getCiCode());
            if(BinaryUtils.isEmpty(useRltList)){
                result.put(rltId, Collections.emptyList());
                continue;
            }
            List<CcCiRltInfo> bltRltList = belRltGroup.get(targetCi.getCiCode());
            List<String> belCiCodeList = new ArrayList<>();
            if(!BinaryUtils.isEmpty(bltRltList)){
                belCiCodeList = bltRltList.stream().filter(each -> each.getTargetCiInfo().getCi().getCiCode().equals(targetCi.getCiCode()))
                        .map(each -> each.getSourceCiInfo().getCi().getCiCode()).distinct().collect(Collectors.toList());
            }
            for (CcCiRltInfo rltInfo : useRltList) {
                if(!rltInfo.getSourceCiInfo().getCi().getCiCode().equals(sourceCi.getCiCode())){
                    continue;
                }
                CcCiInfo serviceCi = rltInfo.getTargetCiInfo();
                String serviceType = serviceCi.getAttrs().get(config.getServiceTypeName());
                if(config.getServiceType1().equals(serviceType)){
                    //若为原生服务，继续判断该原型服务是否属于当前目的端的应用系统
                    if(belCiCodeList.contains(serviceCi.getCi().getCiCode())){
                        list.add(serviceCi);
                    }
                }else{
                    //若为映射服务，进一步查询该映射服务所对应的原生服务(查询映射关系数据)
                    CcCiInfo nativeCi = mapServiceMap.get(serviceCi.getCi().getCiCode());
                    if(!BinaryUtils.isEmpty(nativeCi) && belCiCodeList.contains(nativeCi.getCi().getCiCode())){
                        list.add(serviceCi);
                    }
                }
            }
            result.put(rltId, list);
        }
        return result;
    }
}
